/*
 * Copyright (c) 2001-2018 GuaHao.com Corporation Limited. All rights reserved.
 * This software is the confidential and proprietary information of GuaHao Company.
 * ("Confidential Information").
 * You shall not disclose such Confidential Information and shall use it only
 * in accordance with the terms of the license agreement you entered into with GuaHao.com.
 */
package com.laxia.config;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

/**
 * @author weishuai
 * @version 1.0
 * @date 2019-03-17 23:12
 */
@Configuration
@Slf4j
public class RestTemplateConfig {

    /**
     * 连接池获取连接的timeout
     */
    public static final int REQ_TIMEOUT = 2000;

    /**
     * 客户端和服务器建立连接的timeout, 超时后会抛出ConnectionTimeoutException
     */
    public static final int CONNECT_TIMEOUT = 3000;

    /**
     * 客户端和服务器建立连接后,客户端从服务器读取数据的timeout,超时后会抛出SocketTimeoutException
     */
    public static final int SO_TIMEOUT = 5000;

    /**
     * 连接池最大并发连接数
     */
    private static final int maxTotalConnections = 600;

    /**
     * 单个路由最大连接
     */
    private static final int maxConnectionsPerRoute = 30;

    /**
     * 基于httpClient客户端的实现，要使用其他http客户端重写该bean即可
     *
     * @return
     */
    @SuppressWarnings("rawtypes")
    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.setRequestFactory(clientHttpRequestFactory());

        //restTemplate默认的HttpMessageConverter
        List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
        List<HttpMessageConverter<?>> messageConvertersNew = new ArrayList<HttpMessageConverter<?>>();

        for (HttpMessageConverter httpMessageConverter : messageConverters) {
            //跳过MappingJackson2HttpMessageConverter
            if (httpMessageConverter instanceof MappingJackson2HttpMessageConverter) {
                continue;
            }
            if (httpMessageConverter instanceof StringHttpMessageConverter) {
                ((StringHttpMessageConverter) httpMessageConverter).setDefaultCharset(Charset.forName("utf-8"));
                break;
            }
            messageConvertersNew.add(httpMessageConverter);
        }
        //添加fastjson转换器
        messageConvertersNew.add(fastJsonHttpMessageConverter());

        return restTemplate;
    }

    protected HttpMessageConverter<Object> fastJsonHttpMessageConverter() {
        //MediaType
        List<MediaType> mediaTypes = new ArrayList<>();
        mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);

        //FastJsonConfig
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteMapNullValue, SerializerFeature.QuoteFieldNames);

        //创建FastJsonHttpMessageConverter4    Spring 4.2后使用
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
        fastJsonHttpMessageConverter.setSupportedMediaTypes(mediaTypes);
        fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);

        return fastJsonHttpMessageConverter;
    }

    protected HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {
        try {
            HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();

            //开始设置连接池
            PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
            poolingHttpClientConnectionManager.setMaxTotal(maxTotalConnections);
            poolingHttpClientConnectionManager.setDefaultMaxPerRoute(maxConnectionsPerRoute);
            httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);

            HttpClient httpClient = httpClientBuilder.build();
            // httpClient连接配置
            HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
            clientHttpRequestFactory.setReadTimeout(SO_TIMEOUT);
            clientHttpRequestFactory.setConnectionRequestTimeout(REQ_TIMEOUT);
            clientHttpRequestFactory.setConnectTimeout(CONNECT_TIMEOUT);
            return clientHttpRequestFactory;
        } catch (Exception e) {
            log.error("初始化clientHttpRequestFactory出错", e);
        }
        return null;
    }

}